feat: add distributed map operation - #1
Conversation
- Add ctx.distributed_map with inline, S3, and reader sources - Add DistributedMapConfig, processor, completion, and destination config types - Add DistributedMapResult/Summary result types and DistributedMapError - Add function-authoring helpers for item and batch handlers - Serialize the DISTRIBUTED_MAP operation and add its executor
yaythomas
left a comment
There was a problem hiding this comment.
this won't work against installed botocore yet. the checkpoint goes through the boto3 lambda client, which rejects unknown structure members at param-validation time, so every ctx.distributed_map call fails client-side with ParamValidationError until a botocore release ships the distributed-map model.
bump the boto3 minimum pin once this available. so the failure mode becomes an install-time constraint instead of a runtime one.
| """Processor that reports the ids of failed items, with all others marked succeeded.""" | ||
| return cls( | ||
| function_name=name, | ||
| response_mode="ReportBatchItemFailures", |
There was a problem hiding this comment.
this correct? vs REPORT_BATCH_ITEM_FAILURES ?
shouldn't this be captured in an enum?
enum DistributedMapFunctionResponseType {
REPORT_BATCH_ITEM_FAILURES
REPORT_BATCH_ITEM_RESULTS
}
which would have helped prevent the drift between wire-value and serialization classes.
| class DistributedMapSource: | ||
| """Source configuration for a map run.""" | ||
|
|
||
| source_type: str |
There was a problem hiding this comment.
suggestion: this would benefit from being an enum rather than a raw string, matching the other wire enums in this SDK (e.g. OperationType, OperationStatus).
| bucket: str | ||
| key: str | None = None | ||
| prefix: str | None = None | ||
| transform: str | None = None |
There was a problem hiding this comment.
suggestion: this would benefit from being an enum rather than a raw string, matching the other wire enums in this SDK (e.g. OperationType, OperationStatus).
| key: str | None = None | ||
| prefix: str | None = None | ||
| transform: str | None = None | ||
| fmt: str | None = None |
There was a problem hiding this comment.
suggestion: this would benefit from being an enum rather than a raw string, matching the other wire enums in this SDK (e.g. OperationType, OperationStatus).
| uri: str, | ||
| *, | ||
| headers: Sequence[str] | None = None, | ||
| delimiter: str = "COMMA", |
There was a problem hiding this comment.
suggestion: this would benefit from being an enum rather than a raw string, matching the other wire enums in this SDK (e.g. OperationType, OperationStatus).
| WAIT = "WAIT" | ||
| CALLBACK = "CALLBACK" | ||
| CHAINED_INVOKE = "CHAINED_INVOKE" | ||
| DISTRIBUTED_MAP = "DISTRIBUTED_MAP" |
There was a problem hiding this comment.
any other changes necessary here to wire the events in for plugin? are there specific events?
| @@ -0,0 +1,502 @@ | |||
| """Implement the Durable map run operation.""" | |||
There was a problem hiding this comment.
module name could be dmap, avoid underscore
| def _s3_config_to_wire(s3: S3SourceConfig) -> dict[str, Any]: | ||
| """Translate a resolved S3 source config into its wire dict.""" | ||
| result: dict[str, Any] = {"Bucket": s3.bucket} | ||
| if s3.key is not None: |
There was a problem hiding this comment.
repo convention is for this to live on the model
| @@ -0,0 +1,241 @@ | |||
| """Authoring helpers for distributed map processor and reader Lambda functions. | |||
There was a problem hiding this comment.
how about dmap.py, mirroring the existing waits.py / operation/wait.py split? keeping it un-exported from the root package (as you already do) seems right.
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @functools.lru_cache(maxsize=1) |
There was a problem hiding this comment.
is reading the pattern out of botocore's service model worth it here vs a simpler non-empty/length check?
the fine grammar gets enforced by the service anyway, and if botocore ever drops pattern/max from the shape metadata this starts raising KeyError on every processor construction.
Summary
Adds the distributed map operation (
ctx.distributed_map) to the Python SDK:A map run processes a bounded dataset in parallel. A customer starts a map run from a durable function, naming a source to read items from, a processor function to invoke per batch, and concurrency, retry, and failure settings. The service reads items from the source, groups them into batches, invokes the processor for each batch, retries failures, tracks progress, routes successful results and failed items to destinations, and reports completion.
Changes
concurrency/models.pyDistributedMapSummary: whatctx.distributed_mapreturns, describes run's overall outcome.DistributedMapResult: returned fromctx.distributed_mapwhen inline result collection is enabled. Contains individual map run item outcomes.DistributedMapResultItemandDistributedMapItemError: represent a single item's result / errorconfig.pyDistributedMapConfig: optional settings for distributed mapDistributedMapSource: describes where map run items come from (inline list, S3, or a custom reader)DistributedMapProcessor: describes the Lambda that processes items and how outcomes are reported backProcessorRetryConfig: configures how failing items are retriedDistributedMapCompletionConfig: defines item failure thresholds for marking the overall map run failedSuccessDestination,FailureDestination,DistributedMapDestinationConfig,DistributedMapDestination: for routing successful and failed item records to S3context.pyctx.distributed_map: the entry point a customer calls to run a distributed mapdistributed_map_helpers.pyoperation/distributed_map.pylambda_service.pystate.pyexceptions.pyDistributedMapError: the error a customer catches when a run or an item fails__init__.pyTests
tests/operation/distributed_map_test.pytests/context_test.pytests/e2e/distributed_map_int_test.pyctx.distributed_maptests, mocking backend responses: suspend / resume, collect results, throw on failuretests/distributed_map_helpers_test.pytests/e2e/distributed_map_helpers_int_test.pyTODO
Future Tasks
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.